package cn.ycoz.cloud.windspeed.template;

import org.apache.velocity.Template;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.RuntimeInstance;
import org.apache.velocity.runtime.parser.ParseException;
import org.apache.velocity.runtime.parser.node.SimpleNode;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.StringWriter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import static org.apache.commons.lang3.exception.ExceptionUtils.getMessage;

/**
 * Velocity 模板引擎的上下文运行环境
 */
public class VelocityEnv {

    private final static Logger logger = LoggerFactory.getLogger(VelocityEnv.class);

    private final Map<String, SimpleNode> globalCache = new ConcurrentHashMap<>();

    private RuntimeInstance ri = new RuntimeInstance();

    private VelocityEngine ve = new VelocityEngine();

    public VelocityEnv() {
        ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
        ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
        ve.init();
    }

    public Set<String> getNames() {
        return globalCache.keySet();
    }

    public boolean put(String name, String content) {
        try {
            SimpleNode node = ri.parse(content, name);
            globalCache.put(name, node);
            return true;
        } catch (ParseException e) {
            logger.error("{}.{}:{}", getMessage(e), name, content);
        }
        return false;
    }

    public StringWriter process(String name, Map<String, Object> data) {
        Template resource = ve.getTemplate("velocity.vm");
        SimpleNode node = globalCache.get(name);
        resource.setData(node);
        resource.initDocument();

        org.apache.velocity.VelocityContext ctx = new org.apache.velocity.VelocityContext();
        ctx.setCurrentResource(resource);

        Set<Map.Entry<String, Object>> entrySet = data.entrySet();
        for (Map.Entry<String, Object> entry : entrySet) {
            ctx.put(entry.getKey(), entry.getValue());
        }

        StringWriter sw = new StringWriter();
        resource.merge(ctx, sw);
        return sw;
    }

}
